﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TekaMUD.Engine.Blocks;
using TekaMUD.Engine.IO;
using TekaMUD.Engine.Behaviour;

namespace TekaMUD.Engine.Commands
{
	public class ExplorationActions
	{
		/// <summary>
		/// Opens a door or a box.
		/// </summary>
		public static void Open(Command c)
		{
			// Either opens instances of Door or IBox

			if (c.BoundArguments.Length == 0)
			{
				Messenger.SendAgent(c.Player, "Open what?");
				return;
			}

			foreach(GameEntity ge in c.BoundArguments)
				if (ge is Door)
				{
					Door d = (Door)ge;

					if (d.Opened)
					{
						Messenger.SendAgent(c.Player, "The " + d.AdjectivizedName + " is already open.");
						return;
					}

					bool result;

					if(d.RequireKey)
					{
						List<Key> keys = new List<Key>();


						foreach(GameObject go in c.Player.Backpack.GetByType(typeof(Key)))
							keys.Add((Key) go);

						result = d.Open(keys.ToArray());
					}
					else
					{
						result = d.Open();
					}

					if (result)
						Messenger.SendAgent(c.Player, "You open the " + d.AdjectivizedName);
					else
						Messenger.SendAgent(c.Player, "You are unable to open the " + d.AdjectivizedName + ".");

					return;
				}
				else if (ge is IBox)
				{
					Messenger.SendAgent(c.Player, "Not implemented on boxes."); 
					return;
				}

			Messenger.SendAgent(c.Player, "You can not open that!");
		}

		/// <summary>
		/// Looks at something.
		/// </summary>
		public static void AutoLook(Command c)
		{
			StringBuilder sb = new StringBuilder();

			sb.AppendLine(c.Player.CurrentRoom.LookDescription);

			foreach (KeyValuePair<EnumDirectionType, RoomConnection> exit in c.Player.CurrentRoom.GetAllConnections())
				sb.AppendLine("There is an exit to the " + exit.Value.Direction + ".");

			foreach (GameObject go in c.Player.CurrentRoom.RoomObjects.Contents)
				sb.AppendLine("There is " + go.Article + " " + go.AdjectivizedName + " here.");

			foreach (Player p in World.Current.GetPlayersByRoom(c.Player.CurrentRoom))
				if(p != c.Player)
					sb.AppendLine(p.Name + " is here.");

			foreach (NPC agent in World.Current.GetNpcByRoom(c.Player.CurrentRoom))
				sb.AppendLine(agent.Article + " " + agent.Name + " is here.");

			// Describe room exits.

			// List room players.

			Messenger.SendAgent(c.Player, sb.ToString());

			return;
		}

		/// <summary>
		/// Executes the action with a given set of objects and targets.
		/// </summary>
		public static void Look(Command c)
		{
			string OtherExecutionMsg = "{0} looks at {1}";

			if ((c.BoundArguments == null || c.BoundArguments.Length == 0)
				&& c.CommandNode.ArgumentList.Count > 0 )
			{
				Messenger.SendAgent(c.Player, "There is no such thing here...");
				return;
			}

			if (c.BoundArguments == null || c.BoundArguments.Length == 0)
			{
				
				AutoLook(c);
				return;
			}

			StringBuilder sb = new StringBuilder();

			foreach (GameEntity o in c.BoundArguments)
				if (o is Room)
				{
					Messenger.SendAgent(c.Player, ((o as Room).LookDescription));

					foreach (GameObject go in (o as Room).RoomObjects.Contents)
						sb.AppendLine("There is " + go.Article + " " + go.Name + " here.");

					foreach (Player p in World.Current.GetPlayersByRoom(c.Player.CurrentRoom))
						if(p != c.Player)
							sb.AppendLine( p.Name + " is here.");

				}
				else if (o is NPC)
				{
					NPC npc = o as NPC;
					sb.AppendLine(npc.LookDescription);

				}
				else if (o is GameObject)
				{
					GameObject go = o as GameObject;

					Messenger.SendRoom(c.Player.CurrentRoom, string.Format(OtherExecutionMsg, c.Player.Name, go.AdjectivizedName), c.Player);
					sb.AppendLine(go.LookDescription);
				}
				else if (o is Player)
				{
					Player p = o as Player;

					if (p == c.Player)
					{
						Messenger.SendAgent(c.Player, "You look at yourself...");
					}
					else
					{
						sb.AppendLine("You look at " + p.Name);
						sb.AppendLine(string.Format(OtherExecutionMsg, c.Player.Name, "you"));
						Messenger.SendRoom(c.Player.CurrentRoom, string.Format(OtherExecutionMsg, c.Player.Name, p.Name));
					}

				}
				else
				{
					sb.AppendLine("You can't look at that.");
				}

			Messenger.SendAgent(c.Player, sb.ToString());
		}

		/// <summary>
		/// Examines a target object.
		/// </summary>
		public static void Examine(Command c)
		{
			string OtherExecutionMsg = "{0} examines {1} {2}.";
			string OtherPlayerMsg = "{0} examines {1}.";

			if (c.BoundArguments == null || c.BoundArguments.Length == 0)
			{
				Messenger.SendAgent(c.Player, "Examine what?");
				return;
			}

			if (c.BoundArguments.Length > 1)
			{
				Messenger.SendAgent(c.Player, "You can only examine one object at a time.");
				return;
			}

			foreach (GameEntity o in c.BoundArguments)
				if (o is Room)
				{
					Messenger.SendAgent(c.Player, ((o as Room).ExamineDescription));
				}
				else if (o is NPC)
				{
					NPC npc = o as NPC;
					Messenger.SendAgent(c.Player, npc.ExamineDescription);
				}
				else if (o is GameObject)
				{
					GameObject go = o as GameObject;

					Messenger.SendRoom(c.Player.CurrentRoom, string.Format(OtherExecutionMsg, c.Player.Name, go.Article, go.AdjectivizedName), c.Player);
					Messenger.SendAgent(c.Player, go.ExamineDescription);
				}
				else if (o is Player)
				{
					Player p = o as Player;

					if (p == c.Player)
					{
						Messenger.SendAgent(c.Player, "You examine yourself...");
					}
					else
					{
						Messenger.SendAgent(c.Player, "You examine " + p.Name);
						Messenger.SendAgent(p, string.Format(OtherPlayerMsg, c.Player.Name, "you"));
						Messenger.SendRoom(c.Player.CurrentRoom, string.Format(OtherPlayerMsg, c.Player.Name, p.Name));
					}
				}
				else
				{
					Messenger.SendAgent(c.Player, "You  can't examine that.");
				}
		}


		public static void Weather(Command c)
		{
			if(c.Player.CurrentRoom.Flags == EnumRoomFlags.Indoors)
			{
				Messenger.SendAgent(c.Player, "You can't see the weather indoors!");
				return;
			}

			// Player env:
			EnvData env = c.Player.CurrentRoom.Sector.Continent.Environment;

			StringBuilder sb = new StringBuilder();

			sb.AppendFormat("It's {0} and {1}.\n", env.DescribeSeason(), env.DescribeWeather() );
			sb.AppendFormat(env.DescribeWind());
			sb.Append("\n");

			Messenger.SendAgent(c.Player, sb.ToString());
		}

		public static void Time(Command c)
		{
			// Player env:
			EnvData env = c.Player.CurrentRoom.Sector.Continent.Environment;

			StringBuilder sb = new StringBuilder("Current time: ");
			sb.Append(env.WorldClock.ToString("f"));

			Messenger.SendAgent(c.Player, sb.ToString());
		}
	}
}
